#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 100

int main(int argc, char *argv) {
    int i, j, k;
    double sum;
    double start, end;
    double A[N][N], B[N][N], C[N][N], D[N][N];;
    
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            A[i][j] = j*1;
            B[i][j] = i*j+2;
            C[i][j] = j-i*2;
            D[i][j] = 0; 
        }
    }
    start = omp_get_wtime(); //start time measurement
    
    # pragma omp parallel for private(i, j, k, sum) num_threads(8)
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            sum = 0;
            for (k=0; k < N; k++) {
                sum += A[i][k]*B[k][j];
            }
            C[i][j] = sum;
        }
        
    }
    end = omp_get_wtime(); //end time measurement
    printf("Time of computation: %f seconds\n", end-start);
    
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            sum = 0;
            for (k = 0; k < N; k++) {
                sum += A[i][k] * B[k][j];
            }
            D[i][j] = sum;
        }
    }
    int errors = 0;
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            // Using a small tolerance for floating-point comparison
            if (fabs(C[i][j] - D[i][j]) > 1e-9) { 
                printf("Error at C[%d][%d]: Parallel value = %f, Serial value = %f\n", i, j, C[i][j], D[i][j]);
                errors++;
            }
        }
    }

    if (errors == 0) {
        printf("Data consistency check passed!\n");
    } else {
        printf("Data consistency check failed. Total errors: %d\n", errors);
    }
    
    return(0);
}